//
// Created by martin on 8/3/21.
//

#include <ctype.h>
#include <malloc.h>
#include "strex.h"

/**
 * 将字符串s从子字符串delim处，切分为2个子字符串，分别保存到left和right指向的存储空间
 * @note 切分处delim会被替换为\0(null终结符). 函数调用后会修改原字符串s.
 */
void str_split(char *s, char *left, char *right, const char* delim)
{
    char *s1, *s2;
    s1 = strtok_r(s, delim, &s2);

    if (s1)
        strcpy(left, s1);

    if (s2)
        strcpy(right, s2);
}

/**
 * 裁剪字符串s，移除两端空白字符，裁剪后的字符串保存到长度为n bytes的缓存new_s
 * @note 空白字符由isspace定义，包含：space, '\f', '\n', '\r', '\t', '\v'
 */
void str_trim(const char *s, char *new_s, size_t n)
{
    if (!new_s || n <= 0) return;

    size_t size = strlen(s);
    size_t i = 0, j = size - 1, k;

    while (isspace(s[i])) i++;
    while (j >= i && isspace(s[j])) j--;

    for (k = 0; k < n - 1 && i <= j; i++, k++) {
        new_s[k] = s[i];
    }
    new_s[k] = '\0';
}

/**
 * 裁剪字符串s首尾，结果也保存到s
 * @note s不能是字符串常量. 非线程安全
 */
void str_trim_self(char *s)
{
    if (!s) return;
    size_t size = strlen(s);
    char *new_s = (char *)malloc((size + 1) * sizeof(char));
    if (!new_s) return;

    str_trim(s, new_s, size + 1); /* 裁剪s首尾，保存到new_s */
    strcpy(s, new_s); /* 将字符串new_s拷贝回s */

    free(new_s); /* 释放malloc资源 */
}

/**
 * 将字符串s转换为大写字符串
 * @note 只转换s中的英文字符，其他字符不变
 */
void str_toupper(char *s)
{
    while (*s != '\0') {
        *s = (char)toupper(*s);
        ++s;
    }
}

/**
 * 将字符串s转换为小写字符串
 * @note 只转换s中的英文字符，其他字符不变
 */
void str_tolower(char *s)
{
    while (*s != '\0') {
        *s = (char)tolower(*s);
        ++s;
    }
}

/**
 * 判断字符串s是否包含能通过条件测试func的字符
 */
int  str_contains_if(char *s, typeof(isspace) func)
{
    if (!s) return 0;
    if (!func) return 1;

    while (*s != '\0') {
        if (func(*s)) return 1;
        s++;
    }
    return 0;
}

/**
 * 判断字符串s是否包含不能通过条件测试func的字符
 */
int  str_contains_ifnot(char *s, typeof(isspace) func)
{
    if (!s) return 0;
    if (!func) return 1;

    while (*s != '\0') {
        if (!func(*s)) return 1;
        s++;
    }
    return 0;
}


int str_start_with(const char *s, char c)
{
    if (!s) return 0;
    if (*s == c) {
        return 1;
    }

    return 0;
}

/**
 * 判断字符串s是否以字符c结尾
 * @param s 待判断的字符串
 * @param c 要判断结尾结尾字符是否为指定的目标字符
 * @return 判断结果
 */
int str_end_with(const char *s, char c)
{
    if (!s) return 0;
    size_t len = strlen(s);
    if (s[len - 1] == c) {
        return 1;
    }

    return 0;
}

/**
 * 替换将字符串s中所有指定字符
 * @param s 要替换的字符串
 * @param old_c 要被替换的字符
 * @param new_c 替换后的字符
 * @return s中被替换的字符数
 */
int str_replace_char(char *s, char old_c, char new_c)
{
    int n = 0;

    while (*s) {
        if (*s == old_c) {
            *s = new_c;
            n++;
        }
        s++;
    }
    return n;
}